// 版权所有 Epic Games, Inc. 保留所有权利。

#include "AbilityTask_GrantNearbyInteraction.h"

#include "AbilitySystemComponent.h"
#include "Engine/OverlapResult.h"
#include "Engine/World.h"
#include "GameFramework/Controller.h"
#include "Interaction/IInteractableTarget.h"
#include "Interaction/InteractionOption.h"
#include "Interaction/InteractionQuery.h"
#include "Interaction/InteractionStatics.h"
#include "Physics/LyraCollisionChannels.h"
#include "TimerManager.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(AbilityTask_GrantNearbyInteraction)

UAbilityTask_GrantNearbyInteraction::UAbilityTask_GrantNearbyInteraction(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
}

/**
 * 为附近的交互者授予能力
 * @param OwningAbility 拥有此任务的游戏能力
 * @param InteractionScanRange 交互扫描范围
 * @param InteractionScanRate 交互扫描频率
 * @return 创建的 UAbilityTask_GrantNearbyInteraction 对象
 */
UAbilityTask_GrantNearbyInteraction* UAbilityTask_GrantNearbyInteraction::GrantAbilitiesForNearbyInteractors(UGameplayAbility* OwningAbility, float InteractionScanRange, float InteractionScanRate)
{
	UAbilityTask_GrantNearbyInteraction* MyObj = NewAbilityTask<UAbilityTask_GrantNearbyInteraction>(OwningAbility); // 创建新的能力任务对象
	MyObj->InteractionScanRange = InteractionScanRange; // 设置交互扫描范围
	MyObj->InteractionScanRate = InteractionScanRate; // 设置交互扫描频率
	return MyObj; // 返回创建的对象
}

/**
 * 激活任务
 */
void UAbilityTask_GrantNearbyInteraction::Activate()
{
	SetWaitingOnAvatar(); // 设置等待角色

	UWorld* World = GetWorld(); // 获取世界
	World->GetTimerManager().SetTimer(QueryTimerHandle, this, &ThisClass::QueryInteractables, InteractionScanRate, true); // 设置定时器定期查询可交互对象
}

/**
 * 任务销毁时调用
 * @param AbilityEnded 能力是否结束
 */
void UAbilityTask_GrantNearbyInteraction::OnDestroy(bool AbilityEnded)
{
	if (UWorld* World = GetWorld()) // 如果世界存在
	{
		World->GetTimerManager().ClearTimer(QueryTimerHandle); // 清除查询定时器
	}

	Super::OnDestroy(AbilityEnded); // 调用父类销毁方法
}

/**
 * 查询可交互对象
 */
void UAbilityTask_GrantNearbyInteraction::QueryInteractables()
{
	UWorld* World = GetWorld(); // 获取世界
	AActor* ActorOwner = GetAvatarActor(); // 获取角色拥有者
	
	if (World && ActorOwner) // 如果世界和角色拥有者都存在
	{
		FCollisionQueryParams Params(SCENE_QUERY_STAT(UAbilityTask_GrantNearbyInteraction), false); // 碰撞查询参数

		TArray<FOverlapResult> OverlapResults; // 重叠结果数组
		World->OverlapMultiByChannel(OUT OverlapResults, ActorOwner->GetActorLocation(), FQuat::Identity, Lyra_TraceChannel_Interaction, FCollisionShape::MakeSphere(InteractionScanRange), Params); // 多通道重叠检测

		if (OverlapResults.Num() > 0) // 如果有重叠结果
		{
			TArray<TScriptInterface<IInteractableTarget>> InteractableTargets; // 可交互目标数组
			UInteractionStatics::AppendInteractableTargetsFromOverlapResults(OverlapResults, OUT InteractableTargets); // 从重叠结果中追加可交互目标
			
			FInteractionQuery InteractionQuery; // 交互查询
			InteractionQuery.RequestingAvatar = ActorOwner; // 设置请求角色
			InteractionQuery.RequestingController = Cast<AController>(ActorOwner->GetOwner()); // 设置请求控制器

			TArray<FInteractionOption> Options; // 交互选项数组
			for (TScriptInterface<IInteractableTarget>& InteractiveTarget : InteractableTargets) // 遍历可交互目标
			{
				FInteractionOptionBuilder InteractionBuilder(InteractiveTarget, Options); // 交互选项构建器
				InteractiveTarget->GatherInteractionOptions(InteractionQuery, InteractionBuilder); // 收集交互选项
			}

			// 检查是否有选项需要在可以使用之前授予用户能力。
			for (FInteractionOption& Option : Options) // 遍历交互选项
			{
				if (Option.InteractionAbilityToGrant) // 如果有需要授予的交互能力
				{
					// 授予能力给 GAS，否则无法执行交互操作。
					FObjectKey ObjectKey(Option.InteractionAbilityToGrant); // 创建对象键
					if (!InteractionAbilityCache.Find(ObjectKey)) // 如果缓存中不存在
					{
						FGameplayAbilitySpec Spec(Option.InteractionAbilityToGrant, 1, INDEX_NONE, this); // 创建游戏能力规格
						FGameplayAbilitySpecHandle Handle = AbilitySystemComponent->GiveAbility(Spec); // 授予能力
						InteractionAbilityCache.Add(ObjectKey, Handle); // 添加到缓存
					}
				}
			}
		}
	}
}